/*
* Copyright (c) 2011 Connection Road.  All rights reserved.
* This program and the accompanying material are made available
* under the terms of the Eclipse Public Licnese v1.0 which is
* available at http://www.eclipse.org/legal/epl-v10.html
*/

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using CrSyncFilesForms.Properties;
using CrSyncFilesForms.Utils;
using CrSyncFilesUtils;


namespace CrSyncFilesForms {
    public partial class CrSyncUiSubFolders : Form {
        public CrSyncUiSubFolders() {
            InitializeComponent();
            TreeNodes = new Dictionary<string, TreeNode>();
            SubFoldersExclusionList = new List<string>();
        }

        public CrSyncUiSubFolders(FileSyncPairInfo folderPair) {
            InitializeComponent();

            TreeNodes = new Dictionary<string, TreeNode>();
            
            FolderPair = folderPair;
            PairManager = ApplicationGlobals.PairManager;
            LabelSourcePath.Text = FolderPair.LeftFolder.Path;
            LabelDestinationPath.Text = FolderPair.RightFolder.Path;
            LabelPairName.Text = FolderPair.FolderPairName;
            Text = Resources.TEXT_SELECT_SUBFOLDERS_FOR + FolderPair.FolderPairName;
            SubFoldersExclusionList = new List<string>(FolderPair.SubDirectoryExclusionList);
        }

        public override sealed string Text
        {
            get { return base.Text; }
            set { base.Text = value; }
        }

        public FileSyncPairInfo FolderPair { get; set; }
        public FileSyncPairManager PairManager { get; set; }
        public List<string> SubFoldersExclusionList { get; set; }

        private Dictionary<string, TreeNode> TreeNodes { get; set; }

        private bool IsSubFolderExcluded(string relativePath)
        {
            if (SubFoldersExclusionList.Contains(relativePath))
            {
                return true;
            }

            var leftChildNode = new FileNode(FolderPair.LeftFolder.Path).Join(relativePath);
            var rightChildNode = new FileNode(FolderPair.RightFolder.Path).Join(relativePath);

            foreach (var excludedFolder in SubFoldersExclusionList)
            {
                // Seek left
                var leftParentNode = new FileNode(FolderPair.LeftFolder.Path).Join(excludedFolder);
                if (leftChildNode.IsChildOf(leftParentNode))
                {
                    return true;
                }

                // Seek right
                var rightParentNode = new FileNode(FolderPair.RightFolder.Path).Join(excludedFolder);
                if (rightChildNode.IsChildOf(rightParentNode))
                {
                    return true;
                }
            }
            return false;

        }

        private void CallBackLoad(object sender, EventArgs e) {

            // Color scheme
            BackColor = CRSyncColors.DialogBackGround;
            LabelHeader.ForeColor = CRSyncColors.HeaderTitle;
            LabelLeftFolder.ForeColor = CRSyncColors.ForeColor;
            LabelRightFolder.ForeColor = CRSyncColors.ForeColor;

            InitializeTreeViews();

            AcceptButton = Button_OK;
            CancelButton = Button_Cancel;

            BackColor = CRSyncColors.DialogBackGround;
        }

        private void CallBackWindowResized(object sender, EventArgs e) {
            //This is the total free space we compare the total width between this window and the two treeviews.
            const int defaultSpacer = 68; 

            //The viewable width for each treeview minus the spacer on each sides.
            var viewableWidth = (Width - defaultSpacer) / 2;

            LeftFolderTree.Width = viewableWidth;
            RightFolderTree.Width = viewableWidth;

            var rightFolderPosition = RightFolderTree.Location.X;
            LabelRightFolder.Left = rightFolderPosition;
        }

        private void InitializeFolderTree(string path, TreeNode parentTreeNode) {
            var fileNode = new FileNode(path);
            var childNodes = fileNode.ChildNodes(null, false);
            foreach(FileNode childNode in childNodes){
                if(childNode.IsDirectory())
                {
                    var currentTreeNode = new TreeNode(childNode.GetFileName());
                    var relativeSubfolderPath = "";
                    parentTreeNode.Nodes.Add(currentTreeNode);
                    
                    if(childNode.Path.Contains(FolderPair.LeftFolder.Path))
                    {
                        relativeSubfolderPath = childNode.GetRelativePathFromRootPath(FolderPair.LeftFolder.Path);
                    }

                    if(childNode.Path.Contains(FolderPair.RightFolder.Path))
                    {
                        relativeSubfolderPath = childNode.GetRelativePathFromRootPath(FolderPair.RightFolder.Path);
                    }

                    
                    TreeNodes.Add(childNode.Path,currentTreeNode);

                    //// Validate directly from the folder pair object
                    //currentTreeNode.Checked = !FolderPair.IsSubFolderExcluded(relativeSubfolderPath);

                    // Validate from the cached objects
                    currentTreeNode.Checked = !IsSubFolderExcluded(relativeSubfolderPath);
                    
                    if(currentTreeNode.Checked)
                    {
                        currentTreeNode.Parent.Checked = true;

                        //// Validate directly from the folder pair object
                        //if(FolderPair.SubDirectoryExclusionList.Contains(relativeSubfolderPath))
                        //{
                        //    FolderPair.SubDirectoryExclusionList.Remove(relativeSubfolderPath);
                        //}

                        // Validate from the cached objects
                        if (IsSubFolderExcluded(relativeSubfolderPath))
                        {
                            SubFoldersExclusionList.Remove(relativeSubfolderPath);
                        }
                    }
                    else 
                    {
                        //// Validate directly from the folder pair object
                        //if (!FolderPair.SubDirectoryExclusionList.Contains(relativeSubfolderPath))
                        //{ 
                        //    FolderPair.SubDirectoryExclusionList.Add(relativeSubfolderPath);
                        //}

                        // Validate from the cached objects
                        if (!IsSubFolderExcluded(relativeSubfolderPath))
                        {
                            SubFoldersExclusionList.Add(relativeSubfolderPath);
                        }
                    }

                    if (childNode.IsDirectory())
                    {
                        currentTreeNode.ExpandAll();
                        InitializeFolderTree(childNode.Path, currentTreeNode);
                    }
                }
            }
            
        }

        private void InitializeTreeViews() {
            LeftFolderTree.Nodes.Clear();
            RightFolderTree.Nodes.Clear();

            LeftFolderTree.CheckBoxes = true;
            RightFolderTree.CheckBoxes = true;

            var leftTreeNode = new TreeNode(FolderPair.LeftFolder.Path);
            var rightTreeNode = new TreeNode(FolderPair.RightFolder.Path);

            leftTreeNode.Checked = true;
            rightTreeNode.Checked = true;

            leftTreeNode.ExpandAll();
            rightTreeNode.ExpandAll();

            InitializeFolderTree(FolderPair.LeftFolder.Path, leftTreeNode);
            InitializeFolderTree(FolderPair.RightFolder.Path, rightTreeNode);

            LeftFolderTree.Nodes.Add(leftTreeNode);
            RightFolderTree.Nodes.Add(rightTreeNode);
        }

        private void CallBackCancel(object sender, EventArgs e)
        {
            SubFoldersExclusionList = new List<string>(FolderPair.SubDirectoryExclusionList);
            TreeNodes = new Dictionary<string, TreeNode>();
            InitializeTreeViews();
            DialogResult = DialogResult.Cancel;
        }

        private void CallBackRightFolderTreeSelection(object sender, TreeViewEventArgs e)
        {
            FolderTreeSelection(e.Node, FolderPair.RightFolder.Path, FolderPair.LeftFolder.Path);
        }

        private void CallBackLeftFolderTreeSelection(object sender, TreeViewEventArgs e)
        {
            FolderTreeSelection(e.Node, FolderPair.LeftFolder.Path, FolderPair.RightFolder.Path);
        }

        private void FolderTreeSelection(TreeNode treeNode, string sourceRootPath, string destinationRootPath)
        {
            if(treeNode.FullPath != sourceRootPath)
            {
                var fileNode = new FileNode(treeNode.FullPath);
                var relativeSubfolderPath = fileNode.GetRelativePathFromRootPath(sourceRootPath);
                if(treeNode.Checked)
                {
                    //// Save changes directly to the object
                    //if (FolderPair.SubDirectoryExcludes.Contains(relativeSubfolderPath))
                    //{
                    //    FolderPair.SubDirectoryExcludes.Remove(relativeSubfolderPath);
                    //}

                    // Cache the changed object
                    if (IsSubFolderExcluded(relativeSubfolderPath))
                    {
                        SubFoldersExclusionList.Remove(relativeSubfolderPath);
                    }

                    // Make sure parent node is also checked
                    treeNode.Parent.Checked = true;


                }
                else
                {
                    //// Save changes directly to the object
                    //if (!FolderPair.SubDirectoryExcludes.Contains(relativeSubfolderPath))
                    //{
                    //    FolderPair.SubDirectoryExcludes.Add(relativeSubfolderPath);
                    //}

                    // Cache the changed object
                    if (!IsSubFolderExcluded(relativeSubfolderPath))
                    {
                        SubFoldersExclusionList.Add(relativeSubfolderPath);
                    }
                }


                // Perform mirror action but prevent from Stackoverflow exception
                var destinationNode = new FileNode(destinationRootPath).Join(relativeSubfolderPath);
                if (TreeNodes.ContainsKey(destinationNode.Path))
                {
                    var mirrorTreeNode = TreeNodes[destinationNode.Path];

                    // Prevent stack over flow by unbinding previous call backs
                    if (destinationNode.Path.Contains(FolderPair.LeftFolder.Path))
                    {
                        mirrorTreeNode.TreeView.AfterCheck -= CallBackLeftFolderTreeSelection;
                    }
                    else if (destinationNode.Path.Contains(FolderPair.RightFolder.Path))
                    {
                        mirrorTreeNode.TreeView.AfterCheck -= CallBackRightFolderTreeSelection;
                    }

                    // mirror checked value
                    mirrorTreeNode.Checked = treeNode.Checked;

                    // Re-binding previous call backs
                    if (destinationNode.Path.Contains(FolderPair.LeftFolder.Path))
                    {
                        mirrorTreeNode.TreeView.AfterCheck += CallBackLeftFolderTreeSelection;
                    }
                    else if (destinationNode.Path.Contains(FolderPair.RightFolder.Path))
                    {
                        mirrorTreeNode.TreeView.AfterCheck += CallBackRightFolderTreeSelection;
                    }


                }

            }
            else
            {
                if(!treeNode.Checked)
                {
                    treeNode.Checked = true;
                }
            }
            
        }

        private void CallBackAccept(object sender, EventArgs e)
        {
            DialogResult = DialogResult.OK;
        }

        private void CallBackSelectAll(object sender, EventArgs e)
        {
            //// Change the object directly
            //FolderPair.SubDirectoryExcludes = new List<string>();

            // Change the cached objects
            SubFoldersExclusionList = new List<string>();
            
            TreeNodes = new Dictionary<string, TreeNode>();
            InitializeTreeViews();
        }

        private void CallBackUnselectAll(object sender, EventArgs e)
        {
            //// Change the object directly
            //FolderPair.SubDirectoryExcludes = new List<string>();
            
            var leftFileNode = new FileNode(FolderPair.LeftFolder.Path);
            var leftChildNodes = leftFileNode.ChildNodes(null, true);

            var rightFileNode = new FileNode(FolderPair.RightFolder.Path);
            var rightChildNodes = rightFileNode.ChildNodes(null, true);


            foreach(FileNode leftChildNode in leftChildNodes)
            {
                if(leftChildNode.IsDirectory())
                {
                    var leftRelative = leftChildNode.GetRelativePathFromRootPath(leftFileNode.Path);
                    
                    //// Change the object directly
                    //if(!FolderPair.SubDirectoryExcludes.Contains(leftRelative))
                    //{
                    //    FolderPair.SubDirectoryExcludes.Add(leftRelative);
                    //}

                    // Change the cached objects
                    if (!SubFoldersExclusionList.Contains(leftRelative))
                    {
                        SubFoldersExclusionList.Add(leftRelative);
                    }
                }
            }

            foreach(FileNode rightChildNode in rightChildNodes)
            {
                if(rightChildNode.IsDirectory())
                {
                    var rightRelative = rightChildNode.GetRelativePathFromRootPath(rightFileNode.Path);

                    //// Change the object directly
                    //if(!FolderPair.SubDirectoryExcludes.Contains(rightRelative))
                    //{
                    //    FolderPair.SubDirectoryExcludes.Add(rightRelative);
                    //}

                    //Change the cached objects
                    if (!SubFoldersExclusionList.Contains(rightRelative))
                    {
                        SubFoldersExclusionList.Add(rightRelative);
                    }
                }
            }

            TreeNodes = new Dictionary<string, TreeNode>();
            InitializeTreeViews();

        }

        private void CallBackKeyDown(object sender, KeyEventArgs e)
        {
            //if (e.KeyCode == Keys.Escape)
            //{
            //    CallBackCancel(this, new EventArgs());
            //}
        }


    }
}
